package zct.proj.util;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Timer;
import java.util.TimerTask;

import android.os.Handler;
import android.os.Message;
import android.util.Log;


public class ClientThread implements Runnable {

	private Socket socket;
	private Handler handler;
	
//	private static final String HOST = "61.233.65.121";
//	private static final int PORT = 15156;
//	private BufferedReader in = null;
	private DataInputStream in = null;
	private DataOutputStream out = null;
//	private byte[] readBuf = new byte[255];
	final int STATUS_LOGIN = 1;
	final int STATUS_QUERY_STATION = 2;
	final int STATUS_AUDIO_ALARM = 3;
//	private boolean bLoginSuccess = false;
	private boolean bQuerySuccess = false;
//	private boolean bRunnable = true;
	private String stationName;
	
	private final int DATA_HEADER = 0x01;
	private final int DATA_TAIL = 0x03;
	private final int DATA_VOICE_ALARM = 0x11;
	private final int DATA_STATION_INFO = 0x22;
	private final int DATA_STATION_CHANGE = 0x33;
	private final int DATA_QUERY_STATION = 0x40;
	private final int DATA_QUERY_CHANGE = 0x44;
//	private final int DATA_STOP_DATA = 0x45;
	private final int DATA_QUERY_VOICE = 0x46;
//	private final int DATA_STOP_VOICE = 0x47;
	private final int DATA_LOGIN_SUCC = 0x49;
//	private final int DATA_SERVER_DOWN = 0x50;
	private final int DATA_PREFIX = 0x10;
	private final int DATA_SUFFIX = 0x90;
	
	private String mobile = null;
	private int queryCount;
	private int receCountDown;
	private int heartBitError = 0;
//	final String MOBILE_NUMBER = "18737935597";
//	final String MOBILE_NUMBER = "13810193718";
	
	private Timer timer;
	public boolean run = true;
	
	public void endAllTask() {
//		Log.v("clientthread", "endAllTask");
		if (timer != null) {
			timer.cancel();
		}
		if (socket != null) {
			try {
				socket.close();
				socket = null;
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		run = false;
	}
	
	public ClientThread(Handler handler, String sName, String mobile) throws IOException {
//		this.socket = s;
		this.handler = handler;
		stationName = sName;
		this.mobile = mobile;
//		this.mobile = "13810193718";
	}
	
	private boolean send(String data) {
		String toSend = data + "\r\n";
//Log.v("clientthread", "send data......");
		try {
			return send(toSend.getBytes("GBK"));
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return false;
	}
	
	private boolean send(byte[] data) {
		if (socket.isConnected()) {   
			if (!socket.isOutputShutdown()) {
				try {
					out.write(data);
					return true;
				} catch (IOException e) {
					e.printStackTrace();
					CommUtil.writeLog("数据发送失败。");
				}
			}
		}

		return false;
	}
	
	public void run() {
		CommUtil.writeLog("socket线程启动。");
		try {
			socket = new Socket("222.88.94.67", 15156);
			socket.setKeepAlive(true);
			in = new DataInputStream(socket.getInputStream());
			out = new DataOutputStream(socket.getOutputStream());
			CommUtil.writeLog("已经连接至服务器。");
			doLogin();
		} catch (Exception ex) {
			ex.printStackTrace();
			endAllTask();
			postErrorMessage();
			CommUtil.writeLog("创建服务器连接失败：" + ex.getMessage());
			Log.v("socket", "Connect error.");
			return;
//			ShowDialog("登陆异常:" + ex.getMessage());
		}
		
		// 定时发送心跳包
		timer = new Timer();
		TimerTask task = new TimerTask() {
			@Override
			public void run() {
				if (send(new byte[]{(byte) 0xFF})) {
					heartBitError = 0;
				} else {
					heartBitError++;
					if (heartBitError >= 4) {
//						endAllTask();
//						postErrorMessage();
						CommUtil.writeLog("连续" + heartBitError + "次发送心跳包失败。");
					}
				}
			}
		};
		timer.scheduleAtFixedRate(task, 15000, 15000);
		
		TimerTask chkTask = new TimerTask() {
			@Override
			public void run() {
				receCountDown += 2;
//				Log.v("ct", receCountDown + " seconds no data.........");
				if (receCountDown >= 70) {
					// 70秒未收到数据
//					endAllTask();
//					postErrorMessage();
					if (receCountDown % 10 == 0) {
						CommUtil.writeLog(receCountDown + "秒未收到任何数据。");
						Log.v("socket", "70 seconds no data, reconnect............");
					}
					
					if (receCountDown >= 180) {
						// 3分钟无接受数据，强制退出
						endAllTask();
						postErrorMessage();
					}
				}
			}
		};
		timer.scheduleAtFixedRate(chkTask, 2000, 2000);
		
		try {
			byte[] chunk = new byte[4096];
			int chunkSize = 0;
			while (run && !Thread.interrupted()) {
				if(socket.isConnected()){
					if(!socket.isInputShutdown()){
						if ((chunkSize = in.read(chunk)) != -1) {
//							receCountDown = 0;
							dataControl(chunk, chunkSize);
						}
					} else {
						Log.v("socket", "inputshutdown");
					}
				} else {
					Log.v("socket", "not connected");
					endAllTask();
					postErrorMessage();
					CommUtil.writeLog("网络连接中断。");
					break;
				}
				Thread.sleep(50);
			}
		} catch (Exception ex) {
			ex.printStackTrace();
			endAllTask();
			postErrorMessage();
			CommUtil.writeLog("网络连接错误：" + ex.getMessage());
		}
		CommUtil.writeLog("socket线程终止。");
	}
	
	private void postErrorMessage() {
		Message errMsg = new Message();
		errMsg.what = Const.MSG_ERROR;
		handler.sendMessage(errMsg);
		CommUtil.writeLog("发送错误消息至主线程。");
	}

	private void dataControl(byte[] chunk, int size) {
//		StringBuffer sb = new StringBuffer();
//		for (int j = 0; j < size; j++) {
////			sb.append(Integer.toHexString(chunk[j])).append(":").append(chunk[j]).append(" ");
//			String xx = Integer.toHexString(chunk[j] & 0xFF);
//			if (xx.length() == 1) {
//				sb.append("0");
//			}
//			sb.append(xx).append(" ");
//		}
//		Log.v("get data orignal:", sb.toString());
		// 清除失败记数
		receCountDown = 0;
		int curPos = 0;
		byte[] dataFrame = new byte[size];
		for (int i = 0; i < size; i++) {
			// 查找结尾标志，分割、还原数据
			if (chunk[i] == DATA_TAIL) {
				byte[] restData = Arrays.copyOf(dataFrame, curPos + 1);
				restData[curPos] = DATA_TAIL;
				// 处理数据段
				processData(restData);
				if (i < size - 1) {
					dataFrame = new byte[size];
				}
				curPos = 0;
			} else {
				if ((chunk[i] == DATA_PREFIX) && ((chunk[i + 1] & 0xFF) == 0x81)) {
					dataFrame[curPos] = 0x01;
					i++;
				} else if ((chunk[i] == DATA_PREFIX) && ((chunk[i + 1] & 0xFF) == 0x83)) {
					dataFrame[curPos] = 0x03;
					i++;
				} else if ((chunk[i] == DATA_PREFIX) && ((chunk[i + 1] & 0xFF) == DATA_SUFFIX)) {
					dataFrame[curPos] = 0x10;
					i++;
				} else {
					dataFrame[curPos] = chunk[i];
				}
				curPos++;
			}
		}
	}
	//站机如果断线，你会收到{&H1, &H50, &H3}
	
	private void processData(byte[] data) {

		int size = data.length;
		StringBuffer sb = new StringBuffer();
		for (int j = 0; j < size; j++) {
//			sb.append(Integer.toHexString(chunk[j])).append(":").append(chunk[j]).append(" ");
			String xx = Integer.toHexString(data[j] & 0xFF);
			if (xx.length() == 1) {
				sb.append("0");
			}
			sb.append(xx).append(" ");
		}
		Log.v("get data:", sb.toString());
		// 数据类型
		int dataType = 0;
		if (size > 2) {
			dataType = data[1] & 0xFF;
		}
		
		switch (dataType) {
		case DATA_STATION_CHANGE:
			// 0x33
			// 车站变化量
			if (!bQuerySuccess) {
				// 未完成查询全站信息的，抛弃数据
				return;
			}
			int[] ret = stationInfoChanged(data);
			Message msg = new Message();
			msg.what = Const.MSG_SWITHCER_CHANGED;
			msg.getData().putIntArray(Const.MSG_HND, ret);
			handler.sendMessage(msg);
			break;
		case DATA_VOICE_ALARM:
			// 0x11
			// 语音播报
			Message message = new Message();
			message.what = Const.MSG_PLAY_SOUND;
//			Bundle bd = new Bundle();
//			bd.putString(Const.SOUND_HND, getSoundData(data));
//			message.setData(bd);
			message.getData().putString(Const.MSG_HND, getSoundData(data));
			handler.sendMessage(message);
			break;
		case DATA_LOGIN_SUCC:
			// 0x49
//			Log.v("socket", "Login ok, querying all station data...");
			// 请求站机发送所有数据
			doQueryStation();
			TimerTask task = new TimerTask() {
				@Override
				public void run() {
					if (!bQuerySuccess) {
						doQueryStation();
						queryCount++;
						if (queryCount >= 10) {
							Log.v("ClientThread", "retry 10 times, stop.");
							endAllTask();
						} else {
							Log.v("ClientThread", "query data again.");
						}
					}
				}
			};
			timer.scheduleAtFixedRate(task, 2000, 2000);
			break;
		case DATA_QUERY_STATION:
			// 0x40
			// 车站整体信息请求确认
			bQuerySuccess = true;
//			// 请求站机发送语音报警信息
//			doQueryAudioAlarm();
			break;
		case DATA_STATION_INFO:
			// 0x22
			// 收到车站完整数据
			bQuerySuccess = true;
			// 收到车站整体信息，请求发送变化量
			doQueryChangeData();
			// 请求站机发送语音报警信息
			doQueryAudioAlarm();
			Message m = new Message();
			m.what = Const.MSG_STATION_DATA;
			m.getData().putIntArray(Const.MSG_HND, getStationCurrentStateData(data));
			handler.sendMessage(m);
		}
	}
	
	private void doLogin() {
		// 登录
//		socketStatus = STATUS_LOGIN;
		
		send("C+" + mobile + "+" + stationName + "+LYXADZ\r\n");
//		send("C+13810193718+" + stationName + "+LYXADZ\r\n");
	}
	
	private void doQueryStation() {
		// 请求站机发送所有数据
//		socketStatus = STATUS_QUERY_STATION;
		send(new byte[] {DATA_HEADER, DATA_QUERY_STATION, DATA_TAIL});
	}
	
	private void doQueryChangeData() {
		send(new byte[] {DATA_HEADER, DATA_QUERY_CHANGE, DATA_TAIL});
	}
	
//	private void stopQueryData() {
//		send(new byte[] {DATA_HEADER, DATA_STOP_DATA, DATA_TAIL});
//	}
	
	private void doQueryAudioAlarm() {
		// 请求站机发送语音报警信息
//		socketStatus = STATUS_AUDIO_ALARM;
		send(new byte[] {DATA_HEADER, DATA_QUERY_VOICE, DATA_TAIL});
	}
	
//	private void stopQueryAudioAlarm() {
//		send(new byte[] {DATA_HEADER, DATA_STOP_VOICE, DATA_TAIL});
//	}
	
	private String getSoundData(byte[] data) {
		// sx为男声
		if (data[1] == DATA_VOICE_ALARM) {
			String ret = new String(data, 4, data.length - 7, Charset.forName("GBK"));
			Log.v("ClientThread sndstr", ret);
//			Log.v("ClientThread sndstr", new String(data, 4, data.length - 7));
			return ret;
		}
		return null;
	}
	private int[] stationInfoChanged(byte[] data) {
		int count = (data.length - 7) / 2;
		int[] ret = new int[count];
		for (int i = 0; i < count; i++) {
//			byte[] switcher = new byte[] {data[i * 2 + 4], data[i * 2 + 5]};
			short value = CommUtil.byteToShort(data[i * 2 + 4], data[i * 2 + 5]);
//			String txt = Integer.toHexString(data[i * 2 + 4] & 0xFF) + " " + Integer.toHexString(data[i * 2 + 5] & 0xFF);
//			Log.v("socket", "开关：" + txt + "=>" + Math.abs(value) + (value > 0 ? ", 高电平" : ", 低电平"));
			ret[i] = value;
		}
		return ret;
	}
	private int[] getStationCurrentStateData(byte[] data) {
		int[] ret = new int[data.length - 7];
		for (int i = 0; i < ret.length; i++) {
			ret[i] = (data[i + 4] & 0xFF);
		}
		return ret;
	}
}
